package com.ikingtech.platform.business.message.controller;

import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.context.security.Me;
import com.ikingtech.framework.sdk.core.response.R;
import com.ikingtech.framework.sdk.enums.message.MessageChannelStatusEnum;
import com.ikingtech.framework.sdk.enums.message.MessageSendChannelEnum;
import com.ikingtech.framework.sdk.message.api.MessageTemplateApi;
import com.ikingtech.framework.sdk.message.model.*;
import com.ikingtech.framework.sdk.message.model.rpc.MessageBusinessTypeQueryParamDTO;
import com.ikingtech.framework.sdk.message.model.rpc.MessageTemplateBeanDefinitionReportParam;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.framework.sdk.web.annotation.ApiController;
import com.ikingtech.framework.sdk.web.annotation.PostRequest;
import com.ikingtech.platform.business.message.entity.MessageChannelDefinitionDO;
import com.ikingtech.platform.business.message.entity.MessageParamDefinitionDO;
import com.ikingtech.platform.business.message.entity.MessageRedirectDefinitionDO;
import com.ikingtech.platform.business.message.entity.MessageTemplateDO;
import com.ikingtech.platform.business.message.exception.MessageExceptionInfo;
import com.ikingtech.platform.business.message.service.MessageChannelDefinitionService;
import com.ikingtech.platform.business.message.service.MessageParamDefinitionService;
import com.ikingtech.platform.business.message.service.MessageRedirectDefinitionService;
import com.ikingtech.platform.business.message.service.MessageTemplateService;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 消息中心-模板管理
 *
 * @author tie yan
 */
@RequiredArgsConstructor
@ApiController(value = "/message/template", name = "消息中心-模板管理", description = "消息中心-模板管理")
public class MessageTemplateController implements MessageTemplateApi {

    private final MessageTemplateService service;

    private final MessageChannelDefinitionService channelDefinitionService;

    private final MessageParamDefinitionService paramDefinitionService;

    private final MessageRedirectDefinitionService redirectDefinitionService;

    @PostRequest(order = 2, value = "/delete", summary = "删除", description = "删除。")
    public R<Object> delete(@Parameter(name = "id", description = "编号")
                            @RequestBody String id) {
        MessageTemplateDO entity = this.service.getById(id);
        if (null == entity) {
            return R.ok();
        }
        if (!Boolean.TRUE.equals(entity.getConfigurable())) {
            throw new FrameworkException("不允许删除内置模板。");
        }
        entity.setConfigured(false);
        this.service.updateById(entity);
        this.channelDefinitionService.removeByTemplateId(id);
        this.paramDefinitionService.removeNonPreDefinitionByTemplateId(id);
        this.redirectDefinitionService.removeByTemplateId(id);
        return R.ok();
    }

    @PostRequest(order = 2, value = "/update", summary = "更新", description = "更新。")
    public R<Object> update(@RequestBody MessageTemplateBasicDTO template) {
        if (!this.service.exist(template.getId())) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_TEMPLATE_NOT_FOUND);
        }
        this.service.updateById(Tools.Bean.copy(template, MessageTemplateDO.class));
        return R.ok();
    }

    @PostRequest(order = 4, value = "/list/page", summary = "分页查询", description = "分页查询，没有查询结果时返回空列表。")
    public R<List<MessageTemplateBasicDTO>> page(@Parameter(name = "queryParam", description = "查询参数")
                                                 @RequestBody MessageTemplateQueryParamDTO queryParam) {
        List<String> templateIds = new ArrayList<>();
        if (Tools.Str.isNotBlank(queryParam.getChannel())) {
            templateIds.addAll(this.channelDefinitionService.listTemplateIdByChannelType(queryParam.getChannel()));
            if (Tools.Coll.isBlank(templateIds)) {
                return R.ok(new ArrayList<>());
            }
        }
        return R.ok(this.service.listPage(queryParam, templateIds).convertBatch(this::modelConvert));
    }

    @PostRequest(order = 5, value = "/info/list/all", summary = "全量查询", description = "全量查询，没有查询结果时返回空列表。")
    public R<List<MessageTemplateBasicDTO>> all() {
        return R.ok(this.modelConvert(this.service.list()));
    }

    @PostRequest(order = 5, value = "/detail/id", summary = "查询消息模板详情", description = "查询消息模板详情。")
    public R<MessageTemplateDTO> detail(@RequestBody String id) {
        MessageTemplateDO entity = this.service.getById(id);
        if (null == entity) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_TEMPLATE_NOT_FOUND);
        }
        MessageTemplateDTO result = Tools.Bean.copy(entity, MessageTemplateDTO.class);
        List<MessageChannelDefinitionDO> channelDefinitionEntities = this.channelDefinitionService.listByTemplateId(id);
        List<MessageChannelDefinitionDTO> channelDefinitions;
        if (Tools.Coll.isNotBlank(channelDefinitionEntities)) {
            List<String> channelDefinitionIds = Tools.Coll.convertList(channelDefinitionEntities, MessageChannelDefinitionDO::getId);
            List<MessageParamDefinitionDO> paramDefinitionEntities = this.paramDefinitionService.listByChannelDefinitionIds(channelDefinitionIds);
            Map<String, List<MessageParamDefinitionDO>> paramDefinitionMap = Tools.Coll.convertGroup(paramDefinitionEntities, MessageParamDefinitionDO::getChannelDefinitionId);
            List<MessageRedirectDefinitionDO> redirectDefinitionEntities = this.redirectDefinitionService.listByChannelDefinitionIds(channelDefinitionIds);
            Map<String, List<MessageRedirectDefinitionDO>> redirectDefinitionMap = Tools.Coll.convertGroup(redirectDefinitionEntities, MessageRedirectDefinitionDO::getChannelDefinitionId);
            channelDefinitions = Tools.Coll.convertList(channelDefinitionEntities, channelDefinitionEntity -> {
                MessageChannelDefinitionDTO channelDefinition = Tools.Bean.copy(channelDefinitionEntity, MessageChannelDefinitionDTO.class);
                channelDefinition.setConfigured(true);
                if (null != channelDefinition.getChannel()) {
                    channelDefinition.setChannelName(channelDefinition.getChannel().description);
                }
                channelDefinition.setStatusName(channelDefinition.getStatus().description);
                channelDefinition.setParamDefinitions(Tools.Coll.convertList(paramDefinitionMap.get(channelDefinitionEntity.getId()), paramDefinitionEntity -> Tools.Bean.copy(paramDefinitionEntity, MessageParamDefinitionDTO.class)));
                channelDefinition.setRedirectDefinitions(Tools.Coll.convertList(redirectDefinitionMap.get(channelDefinitionEntity.getId()), redirectDefinitionEntity -> Tools.Bean.copy(redirectDefinitionEntity, MessageRedirectDefinitionDTO.class)));
                return channelDefinition;
            });
            channelDefinitions.addAll(this.previewChannelDefinition(id, Tools.Coll.convertList(channelDefinitionEntities, channelDefinitionEntity -> MessageSendChannelEnum.valueOf(channelDefinitionEntity.getChannel()))));
        } else {
            channelDefinitions = this.previewChannelDefinition(id);
        }
        result.setChannelDefinitions(channelDefinitions);
        return R.ok(result);
    }

    @PostRequest(order = 5, value = "/business-type/list", summary = "查询业务模块列表", description = "查询业务模块列表，没有查询结果时返回空列表。")
    public R<List<MessageBusinessTypeDTO>> listBusinessType(@RequestBody MessageBusinessTypeQueryParamDTO queryParam) {
        List<MessageTemplateDO> entities = this.service.listBusinessKeyAndBusinessName(queryParam.getBusinessName());
        Map<String, List<MessageTemplateDO>> templateMap = Tools.Coll.convertGroup(entities, MessageTemplateDO::getBusinessKey);
        List<MessageBusinessTypeDTO> result = new ArrayList<>();
        if (Boolean.TRUE.equals(queryParam.getExcludeAllTemplateConfigured())) {
            for (Map.Entry<String, List<MessageTemplateDO>> entry : templateMap.entrySet()) {
                if (Tools.Coll.contains(entry.getValue(), MessageTemplateDO::getConfigured, false)) {
                    MessageBusinessTypeDTO messageBusinessType = new MessageBusinessTypeDTO();
                    messageBusinessType.setBusinessKey(entry.getKey());
                    messageBusinessType.setBusinessName(entry.getValue().get(0).getBusinessName());
                    result.add(messageBusinessType);
                }
            }
        } else if (Boolean.TRUE.equals(queryParam.getExcludeNonTemplateConfigured())) {
            for (Map.Entry<String, List<MessageTemplateDO>> entry : templateMap.entrySet()) {
                if (Tools.Coll.contains(entry.getValue(), MessageTemplateDO::getConfigured, true)) {
                    MessageBusinessTypeDTO messageBusinessType = new MessageBusinessTypeDTO();
                    messageBusinessType.setBusinessKey(entry.getKey());
                    messageBusinessType.setBusinessName(entry.getValue().get(0).getBusinessName());
                    result.add(messageBusinessType);
                }
            }
        } else {
            templateMap.forEach((businessKey, templateEntities) -> {
                MessageBusinessTypeDTO messageBusinessType = new MessageBusinessTypeDTO();
                messageBusinessType.setBusinessKey(businessKey);
                messageBusinessType.setBusinessName(templateEntities.get(0).getBusinessName());
                result.add(messageBusinessType);
            });
        }
        return R.ok(result);
    }

    @PostRequest(order = 5, value = "/info/list/business-key", summary = "查询消息模板(业务模块标识)", description = "查询消息模板(业务模块标识)，没有查询结果时返回空列表。")
    public R<List<MessageTemplateBasicDTO>> listInfoByBusinessKey(@Parameter(name = "businessKey", description = "业务模块标识")
                                                                  @RequestBody String businessKey) {
        List<MessageTemplateDO> entities = this.service.listNonConfiguredByBusinessKey(businessKey);
        return R.ok(Tools.Coll.convertList(entities, entity -> Tools.Bean.copy(entity, MessageTemplateBasicDTO.class)));
    }

    @Transactional(rollbackFor = Exception.class)
    @PostRequest(order = 6, value = "/channel/definition/add", summary = "新增消息渠道配置", description = "新增消息渠道配置")
    public R<String> addChannelDefinition(@Parameter(name = "channelDefinition", description = "消息渠道配置信息")
                                          @RequestBody MessageChannelDefinitionDTO channelDefinition) {
        if (this.channelDefinitionService.channelExist(channelDefinition.getTemplateId(), channelDefinition.getChannel().name())) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_CHANNEL_ALREADY_DEFINED);
        }
        MessageTemplateDO templateEntity = this.service.getByIdAndTenantCode(channelDefinition.getTemplateId(), Me.tenantCode());
        templateEntity.setConfigured(true);

        MessageChannelDefinitionDO channelDefinitionEntity = Tools.Bean.copy(channelDefinition, MessageChannelDefinitionDO.class);
        channelDefinitionEntity.setId(Tools.Id.uuid());
        channelDefinitionEntity.setTemplateId(templateEntity.getId());
        channelDefinitionEntity.setTenantCode(Me.tenantCode());
        channelDefinitionEntity.setShowNotification(true);

        this.saveParamAndRedirectDefinition(templateEntity.getId(), channelDefinitionEntity.getId(), channelDefinition);
        this.channelDefinitionService.save(channelDefinitionEntity);
        this.service.updateById(templateEntity);
        return R.ok(channelDefinitionEntity.getId());
    }

    @PostRequest(order = 6, value = "/channel/definition/update", summary = "更新消息渠道配置", description = "更新消息渠道配置")
    public R<Object> updateChannelDefinition(@Parameter(name = "channelDefinition", description = "消息渠道配置信息")
                                             @RequestBody MessageChannelDefinitionDTO channelDefinition) {
        if (!this.channelDefinitionService.exist(channelDefinition.getId())) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_CHANNEL_DEFINITION_NOT_FOUND);
        }
        MessageChannelDefinitionDO entity = Tools.Bean.copy(channelDefinition, MessageChannelDefinitionDO.class);
        entity.setShowNotification(true);
        this.paramDefinitionService.removeById(channelDefinition.getId());
        this.redirectDefinitionService.removeById(channelDefinition.getId());
        this.saveParamAndRedirectDefinition(channelDefinition.getTemplateId(), channelDefinition.getId(), channelDefinition);
        this.channelDefinitionService.updateById(entity);
        return R.ok();
    }

    @PostRequest(order = 6, value = "/channel/definition/enable", summary = "启用消息渠道配置", description = "启用消息渠道配置")
    public R<Object> enableChannelDefinition(@RequestBody String channelDefinitionId) {
        MessageChannelDefinitionDO channelDefinitionEntity = this.channelDefinitionService.getById(channelDefinitionId);
        if (null == channelDefinitionId) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_CHANNEL_DEFINITION_NOT_FOUND);
        }
        channelDefinitionEntity.setStatus(MessageChannelStatusEnum.ENABLED.name());
        this.channelDefinitionService.updateById(channelDefinitionEntity);
        return R.ok();
    }

    @PostRequest(order = 6, value = "/channel/definition/disable", summary = "停用消息渠道配置", description = "停用消息渠道配置")
    public R<Object> disableChannelDefinition(@RequestBody String channelDefinitionId) {
        MessageChannelDefinitionDO channelDefinitionEntity = this.channelDefinitionService.getById(channelDefinitionId);
        if (null == channelDefinitionId) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_CHANNEL_DEFINITION_NOT_FOUND);
        }
        channelDefinitionEntity.setStatus(MessageChannelStatusEnum.DISABLED.name());
        this.channelDefinitionService.updateById(channelDefinitionEntity);
        return R.ok();
    }

    @PostRequest(order = 6, value = "/channel/definition/preview/template-id", summary = "预览消息渠道列表", description = "预览消息渠道列表")
    public R<List<MessageChannelDefinitionDTO>> previewChannelDefinitionByTemplateId(@Parameter(name = "templateId", description = "编号")
                                                                                     @RequestBody String templateId) {
        return R.ok(this.previewChannelDefinition(templateId));
    }

    private List<MessageChannelDefinitionDTO> previewChannelDefinition(String templateId) {
        return this.previewChannelDefinition(templateId, new ArrayList<>());
    }

    private List<MessageChannelDefinitionDTO> previewChannelDefinition(String templateId, List<MessageSendChannelEnum> configuredChannel) {
        List<MessageSendChannelEnum> nonConfiguredChannel = Tools.Array.filter(MessageSendChannelEnum.values(), sendChannel -> !configuredChannel.contains(sendChannel));
        if (Tools.Coll.isBlank(nonConfiguredChannel)) {
            return new ArrayList<>();
        }
        List<MessageParamDefinitionDO> paramDefinitionEntities = this.paramDefinitionService.listPreDefinitionByTemplateId(templateId);
        return Tools.Coll.convertList(nonConfiguredChannel, channel -> {
            MessageChannelDefinitionDTO channelDefinition = new MessageChannelDefinitionDTO();
            channelDefinition.setChannel(channel);
            channelDefinition.setChannelName(channel.description);
            channelDefinition.setStatus(MessageChannelStatusEnum.DISABLED);
            channelDefinition.setStatusName(MessageChannelStatusEnum.DISABLED.description);
            channelDefinition.setConfigured(false);
            channelDefinition.setParamDefinitions(Tools.Coll.convertList(paramDefinitionEntities, entity -> Tools.Bean.copy(entity, MessageParamDefinitionDTO.class)));
            return channelDefinition;
        });
    }

    @PostRequest(order = 6, value = "/param/pre-definition/id", summary = "查询消息参数列表", description = "查询消息参数列表，数据不存在时仍然返回成功,数据为null。")
    public R<List<MessageParamDefinitionDTO>> listPreParamDefinitionById(@Parameter(name = "id", description = "编号")
                                                                         @RequestBody String id) {
        List<MessageParamDefinitionDO> entities = this.paramDefinitionService.listPreDefinitionByTemplateId(id);
        return R.ok(Tools.Coll.convertList(entities, entity -> Tools.Bean.copy(entity, MessageParamDefinitionDTO.class)));
    }

    @Override
    public R<Object> report(@RequestBody MessageTemplateBeanDefinitionReportParam reportParam) {
        this.service.report(reportParam.getBeanDefinitions());
        return R.ok();
    }

    private MessageTemplateBasicDTO modelConvert(MessageTemplateDO entity, Map<String, List<String>> channelNameMap) {
        MessageTemplateBasicDTO template = Tools.Bean.copy(entity, MessageTemplateBasicDTO.class);
        if (channelNameMap.containsKey(entity.getId())) {
            template.setChannelNames(Tools.Coll.join(channelNameMap.get(entity.getId())));
        }
        return template;
    }

    private List<MessageTemplateBasicDTO> modelConvert(List<MessageTemplateDO> entities) {
        List<MessageChannelDefinitionDO> channelDefinitionEntities = this.channelDefinitionService.listByTemplateIds(Tools.Coll.convertList(entities, MessageTemplateDO::getId));
        Map<String, List<String>> channelNameMap = Tools.Coll.convertGroup(channelDefinitionEntities, MessageChannelDefinitionDO::getTemplateId, entity -> MessageSendChannelEnum.valueOf(entity.getChannel()).description);
        return Tools.Coll.convertList(entities, entity -> this.modelConvert(entity, channelNameMap));
    }

    private void saveParamAndRedirectDefinition(String templateId, String channelDefinitionId, MessageChannelDefinitionDTO channelDefinition) {
        if (Tools.Coll.isNotBlank(channelDefinition.getParamDefinitions())) {
            this.paramDefinitionService.saveBatch(Tools.Coll.convertList(channelDefinition.getParamDefinitions(), paramDefinition -> {
                MessageParamDefinitionDO entity = Tools.Bean.copy(paramDefinition, MessageParamDefinitionDO.class);
                entity.setId(Tools.Id.uuid());
                entity.setTemplateId(templateId);
                entity.setChannelDefinitionId(channelDefinitionId);
                entity.setPreDefinition(false);
                entity.setTenantCode(Me.tenantCode());
                return entity;
            }));
        }

        if (Tools.Coll.isNotBlank(channelDefinition.getRedirectDefinitions())) {
            this.redirectDefinitionService.saveBatch(Tools.Coll.convertList(channelDefinition.getRedirectDefinitions(), redirectDefinition -> {
                MessageRedirectDefinitionDO entity = Tools.Bean.copy(redirectDefinition, MessageRedirectDefinitionDO.class);
                entity.setId(Tools.Id.uuid());
                entity.setTemplateId(templateId);
                entity.setChannelDefinitionId(channelDefinitionId);
                entity.setTenantCode(Me.tenantCode());
                return entity;
            }));
        }
    }
}
